package com.example.emos.wx.core.config;

import com.example.emos.wx.user.filter.OAuth2Filter;
import com.example.emos.wx.user.shiro.OAuth2Realm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro框架配置类
 *
 * @Author YinXi
 * @Versin 1.0.0
 * @Date 2023/7/31
 */
@Configuration
public class ShiroConfig {
    /**
     * 封装Realm类对象
     *
     * @param oAuth2Realm 传入的Realm对象之前加过@Component注解可以直接使用，它被Spring框架所管理
     * @return SecurityManager注册到Spring框架中
     */
    //返回给Spring注册的Bean对象并且定义注册的名字是什么，相当于xml文件配置中bean标签中的id属性
    @Bean(name = "securityManager")
    public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
        //SecurityManager是接口，DefaultWebSecurityManager是其一个实现类
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //封装Realm对象
        securityManager.setRealm(oAuth2Realm);
        securityManager.setRememberMeManager(null);
        return securityManager;
    }

    /**
     * 封装Filter对象，设置Filter拦截路径
     *
     * @param securityManager 封装Realm类对象，创建ShiroFilterFactoryBean必须使用到它来作为基础进行创建
     * @param oAuth2Filter    传入的Filter对象进行封装使用之前加过@Component注解可以直接使用，它被Spring框架所管理
     * @return ShiroFilterFactoryBean
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, OAuth2Filter oAuth2Filter) {
        //获得ShiroFilterFactoryBean对象
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        //封装securityManager
        shiroFilter.setSecurityManager(securityManager);

        //封装Filter类的对象，也就是oauth过滤
        Map<String, Filter> filters = new HashMap<>();
        filters.put("oauth2", oAuth2Filter);
        shiroFilter.setFilters(filters);

        //给Filter类设置去拦截什么路径下的Http请求
        //保证数据插入的顺序和保存在map中的顺序是一致的使用LinkedHashMap
        Map<String, String> filterMap = new LinkedHashMap<>();
        //key:请求的路径，value：anon表示不拦截，而使用我们上面定义的oauth2就是拦截
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/durid/**", "anon");
        filterMap.put("/app/**", "anon");
        filterMap.put("sys/login", "anon");
        filterMap.put("/swagger/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/captcha.jpg", "anon");
        filterMap.put("/user/register", "anon");
        filterMap.put("/user/login", "anon");
        filterMap.put("/favicon.ico", "anon");
        filterMap.put("/doc.html", "anon");
        filterMap.put("/**/*.css", "anon");
        filterMap.put("/**/*.js", "anon");
        filterMap.put("/resources/**", "anon");
        filterMap.put("/login","anon");
        filterMap.put("/v2/api-docs-ext", "anon");

        //除了上述路径不要被拦截其他都要被拦截
        filterMap.put("/**", "oauth2");
        //将该map放置在ShiroFilterFactoryBean
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }

    /**
     * 管理Shiro对象生命周期
     *
     * @return LifecycleBeanPostProcessor
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * AOP切面类，在Web方法执行前验证权限
     *
     * @param securityManager 在构建AOP对象的时候需要使用这个对象为基础
     * @return AuthorizationAttributeSourceAdvisor 也就是AOP的切面类
     */
    @Bean("authorizationAttributeSourceAdvisor")
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}
